using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;

using MAPI;

namespace Exchange.Export.MAPIMessageConverter
{
	/// <summary>
	/// Converter class to offer MIME conversion from MAPI messages
	/// </summary>
	public class MessageConverter
	{
		#region Unmanged Imports
		[DllImport("MAPIWrapper.dll",SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
		unsafe public static extern int fnConvertMailMessageToMIME([MarshalAs(UnmanagedType.IUnknown)] Object messageObject, [MarshalAs(UnmanagedType.LPStr)] string szFilename, int flags);
		[DllImport("MAPIWrapper.dll",SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
		unsafe public static extern int fnIsMIMEConversionSupported();
		[DllImport("MAPIWrapper.dll",EntryPoint="#3",  SetLastError=true,		CharSet=CharSet.Unicode, ExactSpelling=true,		CallingConvention=CallingConvention.StdCall)]
		unsafe public static extern int fnExportMailMessage([MarshalAs(UnmanagedType.IUnknown)] Object obj, [MarshalAs(UnmanagedType.LPStr)] String szPath, int type, int hwnd, [MarshalAs(UnmanagedType.LPStr)] String szDirName, ref int ExportedAs);

		#endregion

		#region Public Methods
		/// <summary>
		/// Determines whether MessageConversion is valid in the current environment
		/// </summary>
		/// <returns></returns>
		public static bool IsSupported()
		{
			try
			{
				//Check if IConverterSession is installed and able to use
				int result = fnIsMIMEConversionSupported();
				if (0 != result)
					return false;

				return (0 == result);
			}
			catch (Exception  ex)
			{
				Debug.Write(string.Format("Failed to call 'fnIsMIMEConversionSupported'.\nException Details:\n'{0}'", ex.Message));
				return false;
			}
		}
		/// <summary>
		/// Converts the Message to MIME text
		/// </summary>
		/// <param name="message"></param>
		/// <returns></returns>
		public static string ConvertToMIME(MAPI.Message message)
		{
			//Ensure valid message
			if (null == message)
				throw new ArgumentNullException("Message");

			//Ensure conversion is supported

			//Set flags
			int flags = (int)(MAPITOMINEFLAGS.CCSF_SMTP 
				| MAPITOMINEFLAGS.CCSF_NOHEADERS 
				| MAPITOMINEFLAGS.CCSF_NO_MSGID);
			
			//Create a filename
			string filePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());

			try
			{
				//Convert message
				//int result = fnConvertMailMessageToMIME(message.MAPIOBJECT, filePath, flags);
				int exportedType=0;
				
				int result = fnExportMailMessage(message.MAPIOBJECT, filePath, 5,0,Path.GetTempFileName(),ref exportedType);
				if (0 != result)
				{
					
					if (false == IsSupported())
						throw new InvalidOperationException("This functionality is not supported in the current environment.\nThis conversion requires Microsoft Office Outlook 2003 Service Pack 1.");
					result = fnConvertMailMessageToMIME(message.MAPIOBJECT, filePath, flags);
					if (0 != result)

						throw new InvalidOperationException(string.Format("Failed to convert the message to MIME.\nUnexpected error code: {0}", result));
				}
	
			//Load created file
				using (StreamReader reader = new StreamReader(filePath, Encoding.Default))
				{
					//TODO: Find a better way to search the stream without allocating the string
					string response = reader.ReadToEnd();
					//Parse response and select only HTML response
					Regex regEx = new Regex(@"<[^>\s]*\bhtml\b[^>]*>",RegexOptions.IgnoreCase);
					MatchCollection matches = regEx.Matches(response);
					//Expect a start and an end 'html' element
					if (2 != matches.Count)
						throw new InvalidOperationException("Failed to convert the message to MIME.\nHTML tags are not well formed or do not exist.");

					int startIndex = matches[0].Index;
					int endIndex = matches[1].Index + matches[1].Length;
					return response.Substring(startIndex, (endIndex - startIndex));
				}

			}
			catch (Exception ex)
			{
				Debug.Write(string.Format("Failed to call 'fnConvertMailMessageToMIME'.\nException Details:\n'{0}'", ex.Message));
				throw new InvalidOperationException("Failed to convert the message to MIME.\nUnexpected error", ex);
			}
			finally
			{
				//Delete file (if any)
				if (true == File.Exists(filePath))
					File.Delete(filePath);
			}
		}
		#endregion
	}
}
